package com.kedacom.demo.xmemcached;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.exception.MemcachedException;
import net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator;
import net.rubyeye.xmemcached.utils.AddrUtil;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class MemcacheClient {

	protected Logger logger = LoggerFactory.getLogger(getClass());

	private MemcachedClient client;
	@Resource
	private MemcacheClientConfig config;

	@PostConstruct
	public void init() {
		MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses(config.getServers()));
		builder.setConnectionPoolSize(config.getConnectionPoolSize());
		builder.setSessionLocator(new KetamaMemcachedSessionLocator()); // 设置客户端一致性哈希分布策略
		// builder.setCommandFactory(new BinaryCommandFactory());
		try {
			client = builder.build();
		} catch (IOException e) {
			logger.debug(e.toString());
		}
	}

	public MemcachedClient getClient() {
		return client;
	}

	public void setClient(MemcachedClient client) {
		this.client = client;
	}

	public MemcacheClientConfig getConfig() {
		return config;
	}

	public void setConfig(MemcacheClientConfig config) {
		this.config = config;
	}

	/** 设置缓存值，同时设置缓存过期时间（单位秒） */
	public <T> void set(String key, T value, int expireTime) {
		try {
			getClient().set(key, expireTime, value, config.getTimeout());
			logger.debug("cache {}={}", key, value);
		} catch (TimeoutException e) {
			logger.debug(e.toString());
		} catch (InterruptedException e) {
			logger.debug(e.toString());
		} catch (MemcachedException e) {
			logger.debug(e.toString());
		}
	}

	/** 设置缓存值 */
	public <T> void set(String key, T value) {
		this.set(key, value, config.getExpireTime());
	}

	/** 设置缓存值，key以前缀及实际key组合而成，同时设置缓存过期时间（单位秒） */
	public <T> void set(String keyPrefix, String key, T value, int expireTime) {
		this.set(keyPrefix + key, value, expireTime);
	}

	/** 设置缓存值，key以前缀及实际key组合而成 */
	public <T> void set(String keyPrefix, String key, T value) {
		this.set(keyPrefix + key, value);
	}

	/** 获取缓存值 */
	public <T> T get(String key) {
		try {
			T value = getClient().get(key, config.getTimeout());
			logger.debug("retrieve cache {}={}", key, value);
			return value;
		} catch (TimeoutException e) {
			logger.debug(e.toString());
		} catch (InterruptedException e) {
			logger.debug(e.toString());
		} catch (MemcachedException e) {
			logger.debug(e.toString());
		}
		return null;
	}

	/** 获取缓存值，key以前缀及实际key组合而成 */
	public <T> T get(String keyPrefix, String key) {
		return this.get(keyPrefix + key);
	}

	/** 删除缓存值 */
	public boolean delete(String key) throws MemcachedException {
		for (int i = 0; i < 5; i++) {
			try {
				boolean result = getClient().delete(key, (long) config.getTimeout());
				logger.debug("delete cache {} {}", key, result ? "success" : "fail");
				return result;
			} catch (TimeoutException e) {
				logger.debug(e.toString());
			} catch (InterruptedException e) {
				logger.debug(e.toString());
			} catch (MemcachedException e) {
				logger.debug(e.toString());
			}
		}
		throw new MemcachedException("Operation fail,may be caused by networking or timeout");
	}

	/** 删除缓存值，key以前缀及实际key组合而成 */
	public void delete(String keyPrefix, String key) throws MemcachedException {
		this.delete(keyPrefix + key);
	}

	/** 健康检查 */
	public <T> boolean check(String checkKey, T value) throws TimeoutException, InterruptedException,
			MemcachedException {
		getClient().set(checkKey, config.getExpireTime(), value, config.getTimeout());
		return getClient().get(checkKey, config.getTimeout()) != null ? true : false;
	}

}
